package cn.zwk.domain.system.service.impl;

import cn.zwk.common.constant.AdminConstant;
import cn.zwk.common.exception.BusinessException;
import cn.zwk.domain.system.converter.RoleConverter;
import cn.zwk.domain.system.model.dto.RoleDto;
import cn.zwk.domain.system.model.query.RolePageQuery;
import cn.zwk.domain.system.model.vo.RolePageVo;
import cn.zwk.domain.system.service.IRoleService;
import cn.zwk.repository.RoleMenuRepository;
import cn.zwk.repository.RoleRepository;
import cn.zwk.repository.UserRoleRepository;
import cn.zwk.repository.po.Role;
import cn.zwk.repository.po.RoleMenu;
import cn.zwk.repository.po.UserRole;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;

@Service
public class RoleServiceImpl implements IRoleService {
    @Autowired
    private RoleRepository roleRepository;
    @Autowired
    private RoleConverter roleConverter;
    @Autowired
    private RoleMenuRepository roleMenuRepository;
    @Autowired
    private UserRoleRepository userRoleRepository;

    @Override
    public Page<RolePageVo> listPaged(RolePageQuery queryParams) {
        Page<Role> page = roleRepository.page(queryParams.buildPage(), queryParams.buildQuery());
        return roleConverter.toPageVo(page);
    }

    @Override
    public RoleDto getInfo(Long roleId) {
        Role role = roleRepository.getById(roleId);
        return roleConverter.toRoleDto(role);
    }

    @Override
    public boolean save(RoleDto roleDto) {
        if (!checkRoleNameUnique(roleDto)) {
            throw new BusinessException("新增角色'" + roleDto.getName() + "'失败，角色名称已存在");
        }
        if (!checkRoleCodeUnique(roleDto)) {
            throw new BusinessException("新增角色'" + roleDto.getName() + "'失败，角色编码已存在");
        }
        Role rolePo = roleConverter.toRolePo(roleDto);
        return roleRepository.save(rolePo);
    }

    @Override
    public boolean update(RoleDto roleDto) {
        if (!checkRoleNameUnique(roleDto)) {
            throw new BusinessException("修改角色'" + roleDto.getName() + "'失败，角色名称已存在");
        }
        if (!checkRoleCodeUnique(roleDto)) {
            throw new BusinessException("修改角色'" + roleDto.getName() + "'失败，角色编码已存在");
        }
        Role rolePo = roleConverter.toRolePo(roleDto);
        return roleRepository.updateById(rolePo);
    }

    @Override
    public boolean hasAssignedUsers(List<Long> ids) {
        Long count = userRoleRepository.lambdaQuery()
                .in(UserRole::getRoleId, ids)
                .count();
        return count > 0;
    }

    @Override
    @Transactional
    public boolean remove(List<Long> ids, Boolean force) {
        checkRoleAllowed(ids);
        if (!Boolean.TRUE.equals(force) && hasAssignedUsers(ids)) {
            throw new BusinessException("删除角色失败，存在用户绑定该角色");
        }
        /*删除角色基本信息*/
        roleRepository.removeBatchByIds(ids);
        /*删除菜单关联*/
        roleMenuRepository.lambdaUpdate()
                .in(RoleMenu::getRoleId, ids)
                .remove();
        /*删除用户关联*/
        userRoleRepository.lambdaUpdate()
                .in(UserRole::getRoleId, ids)
                .remove();
        return true;
    }

    @Override
    public void checkRoleAllowed(List<Long> ids) {
        Long count = roleRepository.lambdaQuery()
                .in(Role::getId, ids)
                .eq(Role::getCode, AdminConstant.ADMIN_ROLE)
                .count();
        if (count > 0) throw new BusinessException("不允许操作超级管理员角色");
    }

    @Override
    public List<Long> getRoleMenuIds(Long roleId) {
        return roleMenuRepository.lambdaQuery()
                .eq(RoleMenu::getRoleId, roleId)
                .list()
                .stream()
                .map(RoleMenu::getMenuId)
                .toList();
    }

    @Override
    @Transactional
    public boolean assignMenus(Long roleId, List<Long> menuIds) {
        roleMenuRepository.lambdaUpdate()
                .eq(RoleMenu::getRoleId, roleId)
                .remove();
        if (!CollectionUtils.isEmpty(menuIds)) {
            List<RoleMenu> roleMenus = menuIds.stream()
                    .map(menuId -> new RoleMenu(roleId, menuId))
                    .toList();
            roleMenuRepository.saveBatch(roleMenus);
        }
        return true;
    }

    public boolean checkRoleNameUnique(RoleDto role) {
        Role one = roleRepository.lambdaQuery()
                .eq(Role::getName, role.getName())
                .one();
        return one == null || one.getId().equals(role.getId());
    }

    public boolean checkRoleCodeUnique(RoleDto role) {
        Role one = roleRepository.lambdaQuery()
                .eq(Role::getCode, role.getCode())
                .one();
        return one == null || one.getId().equals(role.getId());
    }

}
